﻿using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SuperSocket.Connection;
using SuperSocket.ProtoBase;
using SuperSocket.Server;
using SuperSocket.Server.Abstractions;
using SuperSocket.Server.Abstractions.Session;
using SuperSocket.Server.Host;
using SuperSocket.WebSocket.Server;
using System.Buffers;
using System.Collections.Concurrent;
using System.Text;

namespace Micro.Socket
{
    public abstract partial class SocketHost
    {
        /// <summary>
        /// 是否清除长时间没通信的客户端
        /// </summary>
        public virtual bool ClearIdleSession { get; set; }

        /// <summary>
        /// 服务端定时器
        /// </summary>
        public virtual Timer ServerTimer { get; set; }

        /// <summary>
        /// 默认端口
        /// </summary>
        private const string DefaultPort = "8021";

        /// <summary>
        /// 监听端口：（多个端口之间用逗号隔开）
        /// </summary>
        public abstract string Prots { get; set; }

        /// <summary>
        /// 客户端Sessions字典
        /// </summary>
        private ConcurrentDictionary<string, SocketClientDto> sessionDic = new ConcurrentDictionary<string, SocketClientDto>();

        /// <summary>
        /// Socket服务
        /// </summary>
        public IHost ServerHost;

        /// <summary>
        /// 服务端推送消息
        /// </summary>
        /// <param name="session"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public virtual async ValueTask Publish(string sessionId, dynamic data, string clientUniqueId = default)
        {
            var socketClientDto = sessionDic.Where(o => o.Value is not null).OrderByDescending(o => o.Value.Client.LastActiveTime)
                .FirstOrDefault(o => o.Value.Client.State == SessionState.Connected && ((!string.IsNullOrEmpty(o.Value.ClientUniqueId) && o.Value.ClientUniqueId == clientUniqueId) || o.Value.Client.SessionID == sessionId)).Value;
            if (socketClientDto is null)
            {
                Console.WriteLine($"【{GetType().Name}】：推送消息异常：客户端不存在或客户端连接已断开！"); return;
            }
            try
            {
                var sendStr = data.GetType() == typeof(string) ? data : JsonConvert.SerializeObject(data);
                await socketClientDto.Client.SendAsync(Encoding.Default.GetBytes(sendStr));
                Console.WriteLine($"【{GetType().Name}】：服务端发送： 消息=【{sendStr}】");
            }
            catch { }
        }

        /// <summary>
        /// 启动Socket服务端
        /// </summary>
        /// <returns></returns>
        public virtual async ValueTask StartAsync(CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(Prots)) Prots = DefaultPort;
            var protList = Prots.Split(',').Select(int.Parse).Select(o => new ListenOptions { Ip = "Any", Port = o, BackLog = 1024 }).ToList();

            //使用自定义的数据包和过滤器创建的服务宿主
            var builder = SuperSocketHostBuilder.Create<DataPackage, DataFilter>()
            //.ConfigureServices((hostContext, services) =>
            //{
            //})
            //配置参数
            .ConfigureSuperSocket(options =>
            {
                options.Name = Guid.NewGuid().ToString();
                if (ClearIdleSession)
                {
                    options.ClearIdleSessionInterval = 30 * 1; // 清空空闲会话的时间间隔, 默认值是120, 单位为秒;
                    options.IdleSessionTimeOut = 65 * 1;//会话空闲超时时间; 当此会话空闲时间超过此值，同时clearIdleSession被配置成true时，此会话将会被关闭; 默认值为300，单位为秒;
                }
                options.Listeners = protList;
            });

            if (ClearIdleSession)
                //使用清理闲置会话
                builder.UseClearIdleSession();
            //使用会话的连接和断开事件
            builder.UseSessionHandler(OnConnectedAsync, OnClosedAsync)
            //使用会话的数据接收时间
            .UsePackageHandler(OnPackageAsync)
            //使用会话容器
            .UseInProcSessionContainer();

            //日志
            ServerHost = builder.ConfigureLogging((hostCtx, loggingBuilder) =>
            {
                //register your logging library here
                loggingBuilder.AddConsole();
            }).Build();

            //启动
            ServerHost.StartAsync().GetAwaiter().GetResult();

            await Task.Run(() =>
            {
                // 创建并启动 Timer 实例，并设置定时器间隔为5分钟
                ServerTimer = new Timer(_ =>
                {
                    try
                    {
                        Console.WriteLine($"【{GetType().Name}】【{Prots}】：客户端数量：{sessionDic.Count()}");
                    }
                    catch { }
                }, default, TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(60 * 5));
            });

            Console.WriteLine($"【Socket：{GetType().Name}】服务启动成功，端口【{Prots}】！");
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        /// <returns></returns>
        public virtual async ValueTask StopAsync(CancellationToken cancellationToken)
        {
            try
            {
                foreach (var v in sessionDic.Values)
                {
                    await v.Client.CloseAsync(CloseReason.ServerShutdown);
                }
                sessionDic.Clear();
                ServerHost = default;
                Console.WriteLine($"{GetType().Name}服务已关闭");
            }
            catch { }
        }

        /// <summary>
        /// 会话的连接事件
        /// </summary>
        /// <param name="session"></param>
        /// <returns></returns>
        public virtual async ValueTask OnConnectedAsync(IAppSession session)
        {
            await ValueTask.CompletedTask;
            var sessionImp = session as WebSocketSession;

            #region 用户名密码较验

            if (sessionImp is null || string.IsNullOrEmpty(sessionImp?.Path))
            {
                //await session.CloseAsync(SuperSocket.Connection.CloseReason.ServerShutdown);
                //Console.WriteLine($"【{GetType().Name}】：用户名密码不存在！");
                //return;
            }
            else
            {
                //var dicParams = QueryHelpers.ParseQuery(sessionImp.Path);
                //if (!(dicParams.ContainsValue(string.Empty) && dicParams.ContainsValue(string.Empty)))
                //{
                //    Console.WriteLine($"【{GetType().Name}】：用户名密码有误！");
                //    await session.CloseAsync(SuperSocket.Connection.CloseReason.ServerShutdown); return;
                //}
            }

            #endregion 用户名密码较验

            while (!sessionDic.ContainsKey(session.SessionID))
            {
                //添加不成功则重复添加
                if (!sessionDic.TryAdd(session.SessionID, new SocketClientDto() { Client = session }))
                    Thread.Sleep(1);
                Console.WriteLine($"【{GetType().Name}】：Socket客户端连接_OnConnectedAsync：客户端ID: 【{session.SessionID}】连接成功！");
            }
        }

        /// <summary>
        /// 会话的断开事件
        /// </summary>
        /// <param name="session"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public virtual async ValueTask OnClosedAsync(IAppSession session, CloseEventArgs e)
        {
            await ValueTask.CompletedTask;
            while (sessionDic.ContainsKey(session.SessionID))
            {
                //移除不成功则重复移除
                if (!sessionDic.TryRemove(session.SessionID, out SocketClientDto? socketClientDto))
                    Thread.Sleep(1);
                Console.WriteLine($"【{GetType().Name}】：Socket客户端连接_OnClosedAsync：客户端ID: 【{session.SessionID}】断开连接！");
            }
        }

        /// <summary>
        /// 数据接收事件
        /// </summary>
        /// <param name="session"></param>
        /// <param name="package"></param>
        /// <returns></returns>
        public virtual async ValueTask OnPackageAsync(IAppSession session, DataPackage package)
        {
            await Task.Run(async () =>
            {
                try
                {
                    string ip = $"{session.RemoteEndPoint}";
                    string getMsg = Encoding.UTF8.GetString(package.Datas);

                    Console.WriteLine($"【{GetType().Name}】：消息接收：客户端ID=【{session.SessionID}】 消息=【{getMsg}】 当前连接数【{sessionDic.Count}】！");
                    await Publish(session.SessionID, getMsg);

                    //string encodeData = string.Join(" ", BitConverter.ToString(package.Datas)).Replace('-', ' ');

                    #region 校验帧头帧尾

                    //var lengthBuffer = new byte[2];
                    //Buffer.BlockCopy(package.Datas, 2, lengthBuffer, 0, lengthBuffer.Length);
                    //var length = BitConverter.ToInt16(lengthBuffer.Reverse().ToArray(), 0); //大端模式，高字节先发送，低字节后发送

                    #endregion 校验帧头帧尾

                    #region 数据获取：比如设备编号

                    //var deviceNoBuffer = new byte[4];
                    //Buffer.BlockCopy(package.Datas, 8, deviceNoBuffer, 0, 4);
                    //var deviceNo = BitConverter.ToUInt32(deviceNoBuffer.Reverse().ToArray(), 0).ToString();

                    #endregion 数据获取：比如设备编号

                    #region 校验CRC16

                    //var crc16Buffer = new byte[2];
                    //Buffer.BlockCopy(package.Datas, length - 4, crc16Buffer, 0, crc16Buffer.Length);
                    //var oldCrc0 = crc16Buffer[0];
                    //var oldCrc1 = crc16Buffer[1];

                    #endregion 校验CRC16

                    #region 去除CRC和帧尾

                    //var noCrcAndEndMarkBuffer = new byte[package.Datas.Length - 4];
                    //Buffer.BlockCopy(package.Datas, 0, noCrcAndEndMarkBuffer, 0, noCrcAndEndMarkBuffer.Length);

                    #endregion 去除CRC和帧尾
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"{GetType().Name}接收数据异常，数据源：{BitConverter.ToString(package.Datas).Replace('-', ' ')}", ex);
                }
            });
        }
    }

    public partial class SocketClientDto
    {
        public string ClientUniqueId { get; set; }
        public IAppSession Client { get; set; }
    }

    /// <summary>
    /// 自定义数据过滤器
    /// </summary>
    public partial class DataFilter : IPipelineFilter<DataPackage>
    {
        public IPackageDecoder<DataPackage> Decoder { get; set; }

        public object Context { get; set; }

        public IPipelineFilter<DataPackage> NextFilter => this;

        public DataPackage Filter(ref SequenceReader<byte> reader)
        {
            DataPackage txtPackage = new DataPackage { Datas = reader.Sequence.ToArray() };
            while (reader.TryRead(out _)) ;
            return txtPackage;
        }

        public void Reset()
        { }
    }

    /// <summary>
    /// 自定义数据包
    /// </summary>
    public partial class DataPackage
    {
        /// <summary>
        /// 功能码
        /// </summary>
        public int FCode { get; set; } = -1;

        /// <summary>
        /// 数据
        /// </summary>
        public byte[] Datas { get; set; }
    }
}